package Lib3d.Physics;


import Lib3d.Vector3d;
import Lib3d.SceneGraph.Impl.ObjectNodeImpl;

import java.awt.Color;

import javax.media.opengl.GL;
import javax.media.opengl.GLAutoDrawable;

/**
 * A spring implementation.
 * 
 * @author Wassim Chegham
 * @version 0.1
 * @category Lib3d.Physics
 * 
 */
public class Spring extends ObjectNodeImpl {

    private static float springConstant = 100.0f;
    private static float springDampingFactor = 1f;
    private final Mass mass1, mass2;

    private final float normalLength;
    private float currentLength;
    private static Vector3d dampingForce = new Vector3d(0, 0, 0);
    private final Constraint constraint;
    private Vector3d color;

    public Spring(final Mass mass1, final Mass mass2) {
        this.mass1 = mass1;
        this.mass2 = mass2;

        this.constraint = new Constraint(this, this.mass1, this.mass2);

        this.normalLength = Vector3d.sub(mass2.getLocation(), mass1.getLocation())
                .length();

        this.currentLength = this.normalLength;

        // friction = -(v1 - v2) * m * g
        // Vector3d.mul(
        // Vector3d.neg(Vector3d.sub(mass1.getVelocity(), mass2.getVelocity())),
        // mass1.getMass() * Force.GRAVITY);

    }

    public static Vector3d getDampingForce() {
        return Spring.dampingForce;
    }

    public static float getSpringConstant() {
        return Spring.springConstant;
    }

    public static float getSpringDampingFactor() {
        return Spring.springDampingFactor;
    }

    public void animate(final float dt) {
        this.constraint.satisfySpringConstraint2(dt);
    }

    public Spring applyForce(Vector3d force) {
        final Vector3d normal = this.mass2.getLocation().getNormal();
        if (normal != null) {
            force = Vector3d.mul(normal, Vector3d.dot(normal, force));
            this.mass2.applyForce(force);
        }
        return this;
    }

    @Override
    public void draw(final GLAutoDrawable gLDrawable) {
        final GL gl = gLDrawable.getGL();

        gl.glPushMatrix();
        gl.glEnable(GL.GL_COLOR_MATERIAL);

        gl.glBegin(GL.GL_LINES);

        gl.glColor3fv(this.color.toBuffer());
        gl.glVertex3fv(this.mass1.getLocation().toBuffer());
        gl.glColor3fv(this.color.toBuffer());
        gl.glVertex3fv(this.mass2.getLocation().toBuffer());

        gl.glEnd();

        gl.glDisable(GL.GL_COLOR_MATERIAL);
        gl.glPopMatrix();

        this.setCurrentLength(Vector3d.sub(this.mass2.getLocation(),
                this.mass1.getLocation()).length());
    }

    public float getCurrentLength() {
        return this.currentLength;
    }

    public float getDeltaLength() {
        return this.currentLength - this.normalLength;
    }

    public Mass getMass1() {
        return this.mass1;
    }

    public Mass getMass2() {
        return this.mass2;
    }

    public float getNormalLength() {
        return this.normalLength;
    }

    public Spring setColor(final Color color) {
        this.color = new Vector3d(color.getRed(), color.getGreen(), color.getBlue());
        return this;
    }

    public void setCurrentLength(final float currentLength) {
        this.currentLength = currentLength;
    }

    @Override
    public String toString() {
        return "[L:" + this.currentLength + ", L0:" + this.normalLength + ", m1:"
                + this.mass1 + ", m2:" + this.mass2 + "]";
    }
}